﻿using System.Collections.Generic;
using System.Linq;

namespace DB.SchemaSync.Library.Models
{
	public enum ModuleType
	{
		Procedure = 1,
		ScalarFunction = 2,
		TableFunction = 3
	}

	/// <summary>
	/// 存储过程函数对象
	/// </summary>
	public class Module : DbObject
	{
		public string Schema { get; set; }
		public string Name { get; set; }
		public ModuleType Type { get; set; }
		public IEnumerable<Parameter> Parameters { get; set; } = Enumerable.Empty<Parameter>();
		public string Body { get; set; }

		/// <summary>
		/// Used internally to troubleshoot hash creation
		/// </summary>
		public string NormalizedDefinition { get; set; }

		/// <summary>
		/// Hash of proc body with whitespace replaced with single space, to guard against tab/space differences introduced by FCTB
		/// </summary>
		public byte[] BodyHash { get; set; }

		public override IEnumerable<string> CreateCommands(SqlSyntax syntax)
		{
			yield return Body;
		}

		public override IEnumerable<string> DropCommands(SqlSyntax syntax)
		{
			switch (Type)
			{
				case ModuleType.Procedure:
					yield return $"DROP PROCEDURE <{ToString()}>";
					break;

				case ModuleType.ScalarFunction:
				case ModuleType.TableFunction:
					yield return $"DROP FUNCTION <{ToString()}>";
					break;
			}
		}

		public override bool IsAltered(DbObject compare)
		{
			var test = compare as Module;
			if (test != null)
			{
				if (!test.BodyHash.SequenceEqual(BodyHash)) return true;
			}
			return false;
		}

		public override string ToString()
		{
			return (!string.IsNullOrEmpty(Schema)) ? $"{Schema}.{Name}" : Name;
		}

		public override bool Equals(object obj)
		{
			var check = obj as Module;
			if (check != null)
			{
				return (Schema ?? string.Empty).ToLower().Equals(check.Schema.ToLower()) && (Name ?? string.Empty).ToLower().Equals(check.Name.ToLower());
			}
			return false;
		}

		public override int GetHashCode()
		{
			return (Schema ?? string.Empty).ToLower().GetHashCode() + (Name ?? string.Empty).ToLower().GetHashCode();
		}

		public override ExcludeObject GetExcludeObject()
		{
			return new ExcludeObject() { Type = "Module", Name = ToString() };
		}
	}
}